#web自动化测试的页面基类
from selenium.webdriver.common.by import By
import time,os
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains import ActionChains
#把每个UI都需要的一些通用的定位元素、操作元素的的代码
class PageBaseWeb(object):
    #初始化
    def __init__(self,driver,base_url=None):
        self.driver=driver
        self.base_url=base_url

    def make_xpath_with_unit_feature(self, loc):
        args = loc.split(",")
        feature = ""  # 返回值

        if len(args) == 2:
            feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        elif len(args) == 3:
            if args[2] == "1":
                feature = "@" + args[0] + "='" + args[1] + "'" + "and "
            elif args[2] == "0":
                feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        return feature

    '''
    函数功能：给简化的xpath，函数返回标准的xpath字符串。
    即:
    如果loc = "text,设置"或"text,设置,0"，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = "text,设置,1"，函数返回"//*[@text='设置']"，情况2。
    如果loc = ["text,设置"] ，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = ["text,设置", "index,20,1", "index1,50"]，函数返回"//*[contains(@text,'设置')and@index='20'andcontains(@index1,'50')]"，情况3。
    如果loc = "//*[contains(@text,'设')]" ，即故意传个正常的xpath字符串，函数返回"//*[contains(@text,'设')]"，情况4。
    '''

    def make_xpath_with_feature(self, loc):
        feature_start = "//*["
        feature_end = "]"
        feature = ""

        # 如果传的是字符串，即情况1和情况2
        if isinstance(loc, str):
            # 如果是正常的xpath，即情况4
            if loc.startswith("//"):
                return loc
            feature = self.make_xpath_with_unit_feature(loc)
        else:  # 如果传的是列表，即情况3
            for i in loc:
                feature += self.make_xpath_with_unit_feature(i)

        feature = feature.rstrip("and ")  # 删除最右侧的"and "
        ret_loc = feature_start + feature + feature_end
        return ret_loc


    #根据元素定位特征定位某元素(自动有等待机制)。
    def find_element(self,loc):
        by=loc[0]
        value=loc[1]
        if by==By.XPATH:#如果定位是XPATH定位，可以简化
            value=self.make_xpath_with_feature(value)
        return self.driver.find_element(by, value)


    def find_elements(self,loc):
        by = loc[0]
        value = loc[1]
        if by == By.XPATH:  # 如果定位是XPATH定位，可以简化
            value = self.make_xpath_with_feature(value)
        return self.driver.find_elements(by, value)

    #打开页面
    def open(self,url):
        self.driver.get(url)

    #函数功能：定位元素loc，并输入数据data
    #适合哪些控件：文本框、密码框、大文本框
    def input(self,loc,data):
        self.find_element(loc).send_keys(data)

    #函数功能：定位元素loc，并清空
    def clear(self,loc):
        self.find_element(loc).clear()

    #函数功能：定位元素loc，并点击
    def click(self,loc):
        self.find_element(loc).click()

    #函数功能：上传单个文件。只适合<input type="file" name="xxx">
    #形参loc：input标签的定位特征
    #形参filePath:要上传的文件的路径。例如:"C:/A/1.png"
    def uploadSingleFile1(self,loc,filePath,timeout=5):
        self.find_element(loc).send_keys(filePath)
        time.sleep(timeout)

    # 函数功能：同时上传多个文件，也支持上传单个文件夹。只适合<input type="file" name="xxx" mulXXX="mulXXX">
    # 形参loc：input标签的定位特征
    # 形参filePaths:要上传的多个文件的路。例如:"C:\A\1.png,C:\A\2.png"或""
    def uploadMulFiles1(self,loc,filePaths,timeout=5):
        if filePaths=="":
            pass
        else:
            filePaths=filePaths.replace("\\","\\\\")
            a=filePaths.split(",")
            b="\n".join(a)
            # # self.find_element(loc).send_keys("C:\\A\\1.png\nC:\\A\\2.png") #OK
            self.find_element(loc).send_keys(b)
            time.sleep(timeout)


    #函数功能：上传单个文件。适合调用windows系统的窗口。使用autoIT技术！
    #形参loc_file：上传文件那个input标签的定位特征！
    #形参uploadExePath:autoIT3脚本编译后的上传文件程序路径！例如"C:/A/uploadFile.exe"
    #形参filePath:你想要上传的文件的路径。注意路径中的斜杠。例如:"C:\A\1.png"
    def uploadSingleFile2(self,loc_file,uploadExePath,filePath,timeout=5):
        # 让文件上传窗口出现
        self.mouse_click(loc_file)
        time.sleep(2)
        # 利用autoIT技术来实现文件上传：操作OS的window窗口
        os.system(uploadExePath+" "+filePath)
        time.sleep(timeout)


    # 函数功能：同时上传多个文件，也支持上传单个文件。适合调用windows系统的窗口。使用autoIT技术！
    # 形参loc_file：上传文件那个input标签的定位特征！
    # 形参uploadExePath:autoIT3脚本编译后的上传文件程序路径！例如"C:/A/uploadFile.exe"
    # 形参filePaths:你想要上传的文件的路径。注意路径中的斜杠。例如:"C:\A\1.png,C:\A\2.png"或"C:\A\1.png" 或""
    def uploadMulFile2(self,loc_file,uploadExePath,filePaths,timeout=5):
        if filePaths=="":
            pass
        else:
            # 让文件上传窗口出现
            self.mouse_click(loc_file)
            time.sleep(2)

            # 利用autoIT技术来实现文件上传：操作OS的window窗口
            # 我们需要拼接成这样的正确格格式：
            # c=r'"C:\A\1.png" "C:\A\2.png" '#最后的一个空格别忘记啦
            # os.system("C:/B/uploadFile.exe "+c)
            c=r''
            a = filePaths.split(",")
            for x in a:
                c+='"'+x+'" '
            os.system(uploadExePath+" "+c)
            time.sleep(timeout)

    #处理JS三种弹出框
    #获取三种JS弹出框的文本内容
    def getTextForJsTanCuKuan(self):
        return self.driver.switch_to.alert.text

    #点击三种JS弹出框的“确定”按钮
    def acceptForJsTanCuKuan(self):
        self.driver.switch_to.alert.accept()

    #点击三种JS弹出框的“取消”按钮
    def dismissForJsTanCuKuan(self):
        self.driver.switch_to.alert.dismiss()

    #为JS的prompt弹出框输入文本
    def inputJsTanCuKuan(self,data):
        self.driver.switch_to.alert.send_keys(data)

    #获取元素loc的某属性attr的值
    def getAttr(self,loc,attr):
        return self.find_element(loc).get_attribute(attr)

    #获取某元素loc的文本内容
    def getText(self,loc):
        return self.find_element(loc).text

    #适合控件:单选按钮
    #形参attr_name:某单选按钮的name属性的值
    #形参attr_value:某单选按钮的value属性的值
    def click_radio(self,attr_name,attr_value):
        loc=By.CSS_SELECTOR,"input[name='"+attr_name+"'][value='"+attr_value+"']"
        ele_input=self.find_element(loc)
        ele_input.click()


    #适合控件：复选框
    #形参attr_name:某复选框选项的name属性的值
    #形参attr_vales:你想要选中的这些复选框选型的value属性的值的列表。例如："dalanqiu,tizuqiu","wanyouxi",""
    def click_checkbox(self,attr_name,attr_values):
        loc=By.NAME,attr_name
        eles=self.find_elements(loc)
        for ele in eles:
            value=ele.get_attribute("value")
            checked=ele.get_attribute("checked")#选中："true"、未选中：None
            if value in attr_values:
                if checked=="true":
                    pass
                else:
                    ele.click()
            else:
                if checked=="true":
                    ele.click()
                else:
                    pass

    #适合控件：下列列表
    #形参attr_select_name:selec标签的name属性的值
    #形参option_text:你想要选中的那个option标签的文本内容！
    def click_select(self,attr_select_name,option_text):
        loc_select=By.NAME,attr_select_name
        ele_select=self.find_element(loc_select)
        Select(ele_select).select_by_visible_text(option_text)

    #iframe框架相关处理
    #切换到某iframe
    def switch_iframe(self,loc_iframe):
        ele_ifame=self.find_element(loc_iframe)
        self.driver.switch_to.frame(ele_ifame)

    #切换到主iframe
    def switch_defaultIframe(self):
        self.driver.switch_to.default_content()


    #切换标签页/切换窗口
    #形参n是第几个窗口。n从0开始.-1：最新打开窗口
    def swicth_window(self,n):
        self.driver.switch_to.window(self.driver.window_handles[n])


    #鼠标操作的相关处理

    #函数功能：鼠标单击某元素loc
    def mouse_click(self,loc):
        ele=self.find_element(loc)
        ActionChains(self.driver).click(ele).perform()

    #函数功能：鼠标双击某元素loc
    def mouse_dbclick(self,loc):
        ele=self.find_element(loc)
        ActionChains(self.driver).double_click(ele).perform()

    #函数功能：鼠标悬停在某元素loc
    def mouse_moveToEle(self,loc):
        ele=self.find_element(loc)
        ActionChains(self.driver).move_to_element(ele).perform()

    #函数功能：滑动垂直滚动条到最底部
    def scrollToFloor(self):
        js1 = "window.scrollTo(0,10000)"
        self.driver.execute_script(js1)

    #网页截图
    def savePng1(self,filePath):
        self.driver.get_screenshot_as_file(filePath)
    def savePng2(self,fileName):
        self.driver.get_screenshot_as_file("./screen/"+fileName+".png")
    def savePng3(self,serviceName,key):
        fileName=serviceName+"_"+key+"_"+time.strftime("%Y%m%d%H%M%S")
        self.driver.get_screenshot_as_file("./screen/" + fileName + ".png")
        return fileName







